from __future__ import annotations

import os
from datetime import datetime, timezone

import pytest
from fastapi.testclient import TestClient

from tldw_Server_API.app.main import app


def _setup_env():
    os.environ["AUTH_MODE"] = "single_user"
    os.environ["SINGLE_USER_API_KEY"] = "unit-test-api-key"
    os.environ["USAGE_LOG_ENABLED"] = "true"
    # Exclude all paths from middleware usage logging to avoid NULL user_id rows
    # interfering with FK-constrained aggregation during this test.
    os.environ["USAGE_LOG_EXCLUDE_PREFIXES"] = "[\"/\"]"


async def _insert_usage_rows_sqlite():
    from tldw_Server_API.app.core.AuthNZ.database import get_db_pool

    pool = await get_db_pool()
    # Create a test user to satisfy FK on usage_daily.user_id
    import uuid as _uuid
    await pool.execute(
        "INSERT OR IGNORE INTO users (uuid, username, email, password_hash, is_active) VALUES (?,?,?,?,1)",
        str(_uuid.uuid4()), "usageuser", "usageuser@example.com", "x"
    )
    user_id = await pool.fetchval("SELECT id FROM users WHERE username = ?", "usageuser")
    # Ensure usage tables exist (migrations may be skipped in some single-user SQLite setups)
    await pool.execute(
        """
        CREATE TABLE IF NOT EXISTS usage_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            user_id INTEGER,
            key_id INTEGER,
            endpoint TEXT,
            status INTEGER,
            latency_ms INTEGER,
            bytes INTEGER,
            bytes_in INTEGER,
            meta TEXT,
            request_id TEXT
        )
        """
    )
    await pool.execute(
        """
        CREATE TABLE IF NOT EXISTS usage_daily (
            user_id INTEGER NOT NULL,
            day DATE NOT NULL,
            requests INTEGER DEFAULT 0,
            errors INTEGER DEFAULT 0,
            bytes_total INTEGER DEFAULT 0,
            bytes_in_total INTEGER DEFAULT 0,
            latency_avg_ms REAL,
            PRIMARY KEY (user_id, day)
        )
        """
    )
    # Backfill legacy tables that may have been created before bytes_in fields existed.
    usage_log_cols = {row["name"] for row in await pool.fetchall("PRAGMA table_info(usage_log)")}
    if "bytes_in" not in usage_log_cols:
        await pool.execute("ALTER TABLE usage_log ADD COLUMN bytes_in INTEGER")
    if "request_id" not in usage_log_cols:
        await pool.execute("ALTER TABLE usage_log ADD COLUMN request_id TEXT")

    usage_daily_cols = {row["name"] for row in await pool.fetchall("PRAGMA table_info(usage_daily)")}
    if "bytes_in_total" not in usage_daily_cols:
        await pool.execute("ALTER TABLE usage_daily ADD COLUMN bytes_in_total INTEGER DEFAULT 0")

    # Insert a few rows for today (ts default CURRENT_TIMESTAMP)
    # Use SQLite parameter placeholders
    await pool.execute(
        "INSERT INTO usage_log (user_id, key_id, endpoint, status, latency_ms, bytes, bytes_in, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
        int(user_id),
        None,
        "/api/v1/chat/completions",
        200,
        50,
        100,
        25,
        None,
    )
    await pool.execute(
        "INSERT INTO usage_log (user_id, key_id, endpoint, status, latency_ms, bytes, bytes_in, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
        int(user_id),
        None,
        "/api/v1/embeddings",
        500,
        150,
        300,
        40,
        None,
    )
    return int(user_id)


@pytest.mark.asyncio
async def test_admin_usage_endpoints_sqlite_smoke(monkeypatch):
    # Arrange environment and singletons
    _setup_env()

    # Reset AuthNZ singletons to pick up new env
    from tldw_Server_API.app.core.AuthNZ.database import reset_db_pool
    from tldw_Server_API.app.core.AuthNZ.settings import reset_settings
    from tldw_Server_API.app.core.AuthNZ.session_manager import reset_session_manager

    await reset_db_pool()
    reset_settings()
    await reset_session_manager()

    headers = {"X-API-KEY": os.environ["SINGLE_USER_API_KEY"]}

    # Start app to run lifespan and ensure migrations
    with TestClient(app, headers=headers) as client:
        # Seed usage_log rows (SQLite)
        u_id = await _insert_usage_rows_sqlite()

        # Trigger aggregation for today
        day_str = datetime.now(timezone.utc).date().isoformat()
        r_agg = client.post(f"/api/v1/admin/usage/aggregate?day={day_str}")
        assert r_agg.status_code == 200, r_agg.text

        # Query daily for today
        r_daily = client.get(f"/api/v1/admin/usage/daily?start={day_str}&end={day_str}")
        assert r_daily.status_code == 200, r_daily.text
        daily = r_daily.json()
        assert "items" in daily and isinstance(daily["items"], list)
        # Expect at least one row for our created user
        assert any(int(row["user_id"]) == int(u_id) for row in daily["items"]), daily

        # Query top users
        r_top = client.get(f"/api/v1/admin/usage/top?start={day_str}&end={day_str}&limit=5")
        assert r_top.status_code == 200, r_top.text
        top = r_top.json()
        assert "items" in top and isinstance(top["items"], list)
        assert len(top["items"]) >= 1

        # WebUI smoke: admin content contains the Usage section
        r_ui = client.get("/webui/tabs/admin_content.html")
        assert r_ui.status_code == 200
        assert "/api/v1/admin/usage/daily" in r_ui.text or "Usage Reports" in r_ui.text
